// exporter.cpp
#include "plugin.h"
#include <map>
#include <vmath.h>


class PRS
{
private:
	Vector3 p;
	Quaternion r;
	Vector3 s;

public:
	PRS();
	PRS(const Vector3& p, const Quaternion& r, const Vector3& s);
	~PRS();

	// Interpolation
	friend PRS Slerp(const PRS& a, const PRS& b, const float& t);


	// set / get
	void SetPosition(const Vector3& p);
	Vector3 GetPosition() const;
	void SetRotation(const Quaternion& r);
	Quaternion GetRotation() const;
	void SetScaling(const Vector3& s);
	Vector3 GetScaling() const;
};
// PRS class implementation
PRS::PRS()
{
	p = Vector3();
	r = Quaternion();
	s = Vector3(1, 1, 1);
}
PRS::PRS(const Vector3& p, const Quaternion& r, const Vector3& s)
{
	this->p = p;
	this->r = r;
	this->s = s;
}

PRS::~PRS()
{

}

// set / get
void PRS::SetPosition(const Vector3& p)
{
	this->p = p;
}
Vector3 PRS::GetPosition() const
{
	return p;
}
void PRS::SetRotation(const Quaternion& r)
{
	this->r = r;
}
Quaternion PRS::GetRotation() const
{
	return r;
}
void PRS::SetScaling(const Vector3& s)
{
	this->s = s;
}
Vector3 PRS::GetScaling() const
{
	return s;
}

static std::string GetFilename(std::string full_path)
{
	char *buf = new char[full_path.size() + 1];
	strcpy(buf, full_path.c_str());

	char *last_slash = strrchr(buf, '/');
	if(!last_slash) {
		last_slash = strrchr(buf, '\\');
	}

	if(last_slash) {
		full_path = std::string(last_slash + 1);
	}
	delete [] buf;
	return full_path;
}

// 3d studio will CAPITALIZE extensions of exported file formats. we do not want that ...
static std::string FixExtension(const std::string &str)
{
	std::string ret = str;
	for (int i=ret.size()-1; i>=0; i--)
	{
		char c = ret[i];
		if (c == '.') break;
		if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
		ret[i] = c;
	}
	return ret;
}

// Export file
int SceneyExportPlugin::DoExport(const TCHAR *name, ExpInterface *ei,
		Interface *i, BOOL suppressPrompts,
		DWORD options)
{
	scene = GetIGameInterface();
	if (!scene)
	{
		return false;
	}

	// Set D3D coord system
	GetConversionManager()->SetCoordSystem(IGameConversionManager::IGAME_D3D); 
	scene->InitialiseIGame(false);
	// select frame 0
	scene->SetStaticFrame(0);

	// open the ouput stream
	fp = fopen(FixExtension(name).c_str(), "w+");
	if (!fp)
	{
		return FALSE;
	}

	fprintf (fp, "<?xml version=\"1.0\"?>\n");
	fprintf(fp, "<scene name=\"%s\">\n", FixExtension(GetFilename(name)).c_str());
	indent++;

	// Process materials
	for (unsigned long i=0; i<scene->GetRootMaterialCount(); i++)
	{
		IGameMaterial* mat = scene->GetRootMaterial(i);
		ProcessMaterial(mat);
	}

	fprintf(fp, "\n");

	// process scene data
	int root_nodes = scene->GetTopLevelNodeCount();
	int nodes = scene->GetTotalNodeCount();

	// process nodes
	for (unsigned int i=0; i<root_nodes; i++)
	{	
		ProcessNode(scene->GetTopLevelNode(i));
	}

	fprintf(fp, "\n");

	// Export meshes
	ExportMeshes();

	// Export Lights
	ExportLights();

	indent--;
	fprintf(fp, "</scene>\n");

	// cleanup
	fclose(fp);
	if (scene)
	{
		scene->ReleaseIGame();
	}

	return TRUE;
}

void SceneyExportPlugin::ProcessSingleNode(IGameNode* node)
{
	GMatrix lmat = node->GetLocalTM();
	GMatrix wmat = node->GetWorldTM();
	GMatrix omat = node->GetObjectTM();

	Indent(fp); fprintf(fp, "<xform obj=\"%s\"\n", node->GetName());
	indent++;
	Indent(fp); fprintf(fp, "pos=\"%f %f %f\"\n",
		lmat.Translation().x, lmat.Translation().y, lmat.Translation().z);
	Indent(fp); fprintf(fp, "rot=\"%f %f %f %f\"\n",
		lmat.Rotation().x, lmat.Rotation().y, lmat.Rotation().z, lmat.Rotation().w);
	Indent(fp); fprintf(fp, "scale=\"%f %f %f\"\n", 
		lmat.Scaling().x, lmat.Scaling().y, lmat.Scaling().z);

	// get pivot point
	INode *max_node = node->GetMaxNode();
	Point3 pivot_pos = max_node->GetObjOffsetPos();
	Quat pivot_rot = max_node->GetObjOffsetRot();
	Point3 pivot_scale = max_node->GetObjOffsetScale().s;
	Quat pivot_quat = max_node->GetObjOffsetScale().q;

	Vector3 ppos(pivot_pos.x, pivot_pos.z, pivot_pos.y);
	Quaternion prot(pivot_rot.w, pivot_rot.x, pivot_rot.z, pivot_rot.y);
	Vector3 pscale(pivot_scale.x, pivot_scale.z, pivot_scale.y);
	Quaternion pqscale(pivot_quat.w, pivot_quat.x, pivot_quat.z, pivot_quat.y);
	pscale.transform(pqscale.get_rotation_matrix());

	Indent(fp); fprintf(fp, "pivotpos=\"%f %f %f\"\n",
		ppos.x, ppos.y, ppos.z);
	Indent(fp); fprintf(fp, "pivotrot=\"%f %f %f %f\"\n",
		prot.v.x, prot.v.y, prot.v.z, prot.s);
	Indent(fp); fprintf(fp, "pivotscale=\"%f %f %f\">\n", 
		pscale.x, pscale.y, pscale.z);

	// get the object that corresponds to the node
	IGameObject* obj = node->GetIGameObject();
	if (!obj)
	{
		//printf("Invalid object!\n---\n");
		return;
	}

	// get the object type
	IGameObject::ObjectTypes type = obj->GetIGameType();

	switch (type)
	{
		case IGameObject::IGAME_LIGHT:
			light_nodes.push_back(node);
			break;
		case IGameObject::IGAME_MESH:
			mesh_nodes.push_back(node);
			break;
		case IGameObject::IGAME_CAMERA:
			break;
	}

	node->ReleaseIGameObject();
	obj = 0;
}

void SceneyExportPlugin::ProcessNode(IGameNode* node)
{
	// process current node
	ProcessSingleNode(node);

	// process children
	for (unsigned int i=0; i<node->GetChildCount(); i++)
	{
		ProcessNode(node->GetNodeChild(i));
	}

	indent--;
	Indent(fp); fprintf(fp, "</xform>\n");
}

static std::string MaxSlotToStr(int slot)
{
	switch (slot)
	{
		case ID_AM:
			return "ambient";
			break;
		case ID_DI:
			return "diffuse";
			break;
		case ID_SP:
			return "specular";
			break;
		case ID_SS:
			return "power";
			break;
		case ID_SI:
			return "lightmap";
			break;
		case ID_OP:
			return "opacity";
			break;
		case ID_BU:
			return "normal";
			break;
	}

	return "unsupported";
}

void SceneyExportPlugin::ProcessMaterial(IGameMaterial* mat)
{
	if (!mat->GetSubMaterialCount()) // don't save multimaterials
	{
		Indent(fp);
		fprintf(fp, "<material name=\"%s\">\n", mat->GetMaterialName());
		indent++;

		Point3 ambient, diffuse, specular, emissive;

		ambient.x = ambient.y = ambient.z = 1.0f;
		if (mat->GetAmbientData())
			mat->GetAmbientData()->GetPropertyValue(ambient);	
		
		diffuse.x = diffuse.y = diffuse.z = 1.0f;
		if (mat->GetDiffuseData())
			mat->GetDiffuseData()->GetPropertyValue(diffuse);	
		


		specular.x = specular.y = specular.z = 1.0f;
		if (mat->GetSpecularData())
			mat->GetSpecularData()->GetPropertyValue(specular);	

		float power = 1.0f;
		if (mat->GetSpecularLevelData())
			mat->GetSpecularLevelData()->GetPropertyValue(power);
		

		emissive.x = emissive.y = emissive.z = 1.0f;
		if (mat->GetEmissiveData())
			mat->GetEmissiveData()->GetPropertyValue(emissive);	
	
		// process texture maps
		std::map<std::string, std::string> texture_unit_name_map;
		unsigned long tex_count = mat->GetNumberOfTextureMaps();
		for (unsigned long i=0; i<tex_count; i++)
		{
			IGameTextureMap* map = mat->GetIGameTextureMap(i);
			// get texture slot
			int slot = map->GetStdMapSlot();
			if (slot == -1) continue;
			std::string tt = MaxSlotToStr(slot);
			if (tt == "unsupported") continue;

			std::string filename = "";

			if (map->IsEntitySupported())
			{
				filename = map->GetBitmapFileName();
			}
			// support only bump of non-supported
			else if (slot == ID_BU)
			{
				Texmap* max_texture = map->GetMaxTexmap();
				int sub_count = max_texture->NumSubTexmaps();
				
				for (int i=0; i<sub_count; i++)
				{
					Texmap *sub_map = max_texture->GetSubTexmap(i);
					if (!sub_map) continue;

					BitmapTex *sub_map_bmp = (BitmapTex*) sub_map;
					filename = sub_map_bmp->GetMapName();
				}
			}
			if (filename.size())
			{
				texture_unit_name_map[tt] = filename;
			}

		} // end texture loop

		// ambient
		Indent(fp); fprintf(fp, "<mattr ");
		indent++;
		fprintf(fp, "name=\"ambient\"\n");
		Indent(fp); fprintf(fp, "value=\"%f %f %f\"\n", ambient.x, ambient.y, ambient.z);
		std::string fname = texture_unit_name_map["ambient"];
		if (fname.size())
		{
			Indent(fp); fprintf(fp, "tex=\"%s\"\n", fname.c_str());
		}
		indent--;
		Indent(fp); fprintf(fp, "/>\n");

		// diffuse
		Indent(fp); fprintf(fp, "<mattr ");
		indent++;
		fprintf(fp, "name=\"diffuse\"\n");
		Indent(fp); fprintf(fp, "value=\"%f %f %f\"\n", diffuse.x, diffuse.y, diffuse.z);
		fname = texture_unit_name_map["diffuse"];
		if (fname.size())
		{
			Indent(fp); fprintf(fp, "tex=\"%s\"\n", fname.c_str());
		}
		indent--;
		Indent(fp); fprintf(fp, "/>\n");

		// specular
		Indent(fp); fprintf(fp, "<mattr ");
		indent++;
		fprintf(fp, "name=\"specular\"\n");
		Indent(fp); fprintf(fp, "value=\"%f %f %f\"\n", specular.x, specular.y, specular.z);
		fname = texture_unit_name_map["specular"];
		if (fname.size())
		{
			Indent(fp); fprintf(fp, "tex=\"%s\"\n", fname.c_str());
		}
		indent--;
		Indent(fp); fprintf(fp, "/>\n");

		// specular power
		Indent(fp); fprintf(fp, "<mattr ");
		indent++;
		fprintf(fp, "name=\"power\"\n");
		Indent(fp); fprintf(fp, "value=\"%f\"\n", power);
		fname = texture_unit_name_map["power"];
		if (fname.size())
		{
			Indent(fp); fprintf(fp, "tex=\"%s\"\n", fname.c_str());
		}
		indent--;
		Indent(fp); fprintf(fp, "/>\n");

		// emissive
		Indent(fp); fprintf(fp, "<mattr\n");
		indent++;
		Indent(fp); fprintf(fp, "name=\"emissive\"\n");
		Indent(fp); fprintf(fp, "value=\"%f %f %f\"\n", emissive.x, emissive.y, emissive.z);
		fname = texture_unit_name_map["emissive"];
		if (fname.size())
		{
			Indent(fp); fprintf(fp, "tex=\"%s\"\n", fname.c_str());
		}
		indent--;
		Indent(fp); fprintf(fp, "/>\n");

		indent--;
		Indent(fp); fprintf(fp, "</material>\n");
	}

	// process sub-materials
	for (unsigned long i=0; i<mat->GetSubMaterialCount(); i++)
	{
		ProcessMaterial(mat->GetSubMaterial(i));
	}
}

void SceneyExportPlugin::ExportMeshes()
{	
	for (int m=0; m<mesh_nodes.size(); m++)
	{
		IGameNode *node = mesh_nodes[m];
		IGameMesh *mesh = (IGameMesh*)node->GetIGameObject();

		// search for a skin modifier
		IGameSkin *skin = 0;
		int num_mod = mesh->GetNumModifiers();
		for (int i=0; i<num_mod; i++)
		{
			IGameModifier *mod = mesh->GetIGameModifier(i);
			IGameModifier::ModType type = mod->GetModifierType();
			if (type == IGameModifier::IGAME_SKINNING)
			{
				skin = (IGameSkin*) mod;
				break;
			}
		}

		if (skin)
		{
			// export the initial pose instead
			mesh = skin->GetInitialPose();
		}

		// initialize data
		mesh->SetCreateOptimizedNormalList(); // make normals (and tangents/binormals) per vertex
		mesh->SetUseWeightedNormals(); // is this better than the default?
		mesh->InitializeData();

		Indent(fp); fprintf(fp, "<object name=\"%s\">\n", node->GetName());
		indent++;

		Indent(fp); fprintf(fp, "<mesh>\n");
		indent++;
		
		// export vertices
		for (int i=0; i<mesh->GetNumberOfVerts(); i++)
		{
			Point3 pt = mesh->GetVertex(i, true);
			Indent(fp); fprintf(fp, "<vertex id=\"%d\" val=\"%f %f %f\"/>\n",
				i, pt.x, pt.y, pt.z);
		}fprintf(fp, "\n");

		// export texcoords
		for (int i=0; i<mesh->GetNumberOfTexVerts(); i++)
		{
			Point2 pt = mesh->GetTexVertex(i);
			Indent(fp); fprintf(fp, "<texcoord0 id=\"%d\" val=\"%f %f\"/>\n",
				i, pt.x, pt.y);
		}fprintf(fp, "\n");

		Quat q = node->GetWorldTM().Rotation();
		Matrix3 mat;
		q.MakeMatrix(mat);
		mat.Invert();

		// export normals
		for (int i=0; i<mesh->GetNumberOfNormals(); i++)
		{
			Point3 pt = mesh->GetNormal(i, true);
			mat.TransformPoints(&pt, 1);

			Indent(fp); fprintf(fp, "<normal id=\"%d\" val=\"%f %f %f\"/>\n",
				i, pt.x, pt.y, pt.z);
		}fprintf(fp, "\n");

		// export binormals
		for (int i=0; i<mesh->GetNumberOfBinormals(); i++)
		{
			Point3 pt = mesh->GetBinormal(i);
			mat.TransformPoints(&pt, 1);

			Indent(fp); fprintf(fp, "<binormal id=\"%d\" val=\"%f %f %f\"/>\n",
				i, pt.x, pt.y, pt.z);
		}fprintf(fp, "\n");

		// export tangents
		for (int i=0; i<mesh->GetNumberOfTangents(); i++)
		{
			Point3 pt = mesh->GetTangent(i);
			mat.TransformPoints(&pt, 1);

			Indent(fp); fprintf(fp, "<tangent id=\"%d\" val=\"%f %f %f\"/>\n",
				i, pt.x, pt.y, pt.z);
		}fprintf(fp, "\n");

		// export faces
		int face_count = mesh->GetNumberOfFaces();
		for (int i=0; i<face_count; i++)
		{
			FaceEx *fx = mesh->GetFace(i);
			Indent(fp); fprintf(fp, "<face id=\"%d\">\n", i);
			indent++;

			IGameMaterial *material = mesh->GetMaterialFromFace(i);
			
			if (material)
			{
				char *mat_name = material->GetMaterialName();
				Indent(fp); fprintf(fp, "<matref name=\"%s\"/>\n", mat_name);
			}
			for (int j=0; j<3; j++)
			{
				Indent(fp); fprintf(fp, "<vref vertex=\"%d\" \
texcoord0=\"%d\" normal=\"%d\" binormal=\"%d\" tangent=\"%d\"/>\n", 
					fx->vert[j], fx->texCoord[j], fx->norm[j], fx->norm[j], fx->norm[j]);
			}

			indent--;
			Indent(fp); fprintf(fp, "</face>\n");
		}

		if (skin)
		{
			for (int i=0; i<skin->GetNumOfSkinnedVerts(); i++)
			{
				Indent(fp); fprintf(fp, "<skinvertex id = \"%d\">\n", i);
				indent++;

				for (int j=0; j<skin->GetNumberOfBones(i); j++)
				{
					Indent(fp); fprintf(fp, "<bone name=\"%s\" weight=\"%f\">\n",
						skin->GetIGameBone(i, j)->GetName(), skin->GetWeight(i, j));
				}

				indent--;
				Indent(fp); fprintf(fp, "</skinvertex>\n");
			}
		}

		indent--;
		Indent(fp); fprintf(fp, "</mesh>\n");

		indent--;
		Indent(fp); fprintf(fp, "</object>\n");

		node->ReleaseIGameObject();

		fprintf(fp, "\n");
	}
}

void SceneyExportPlugin::ExportLights()
{
	for (int l=0; l<light_nodes.size(); l++)
	{
		IGameNode *node = light_nodes[l];
		IGameLight *light = (IGameLight*)node->GetIGameObject();

		if (!light->IsEntitySupported()) continue;

		// Get max lightobject and lightsettings, because some
		// IGame functions like GetAttenStart etc won't work
		INode *max_node = node->GetMaxNode();
		Object *lightobj = max_node->GetObjectRef();
		ObjectState os = max_node->EvalWorldState(0);
		GenLight* max_light = (GenLight*)os.obj;
		struct LightState ls;
		max_light->EvalLightState(0, FOREVER, &ls);

		IGameLight::LightType lt = light->GetLightType();
		std::string type = "omni";
		bool target = false;
		switch (lt)
		{
			case IGameLight::IGAME_OMNI:
				type = "omni";
				break;
			case IGameLight::IGAME_TSPOT:
				type = "spot";
				target = true;
				break;
			case IGameLight::IGAME_FSPOT:
				type = "spot";
				break;

			case IGameLight::IGAME_DIR:
				type = "dir";
				break;
			case IGameLight::IGAME_TDIR:
				type = "dir";
				target = true;
				break;
			default:
				continue; // unsupported light
				break;
		}

		Indent(fp); fprintf(fp, "<object name=\"%s\">\n", node->GetName());
		indent++;

		Indent(fp); fprintf(fp, "<light type=\"%s\"\n", type.c_str());
		indent++;

		Point3 clr;
		clr.x = clr.y = clr.z = 1.0f;
		if (light->GetLightColor())
		{
			light->GetLightColor()->GetPropertyValue(clr);
		}
		else
		{
			clr.x = ls.color.r;
			clr.y = ls.color.g;
			clr.z = ls.color.b;
		}
		Vector4 color(clr.x, clr.y, clr.z, 1);

		Indent(fp); fprintf(fp, "color=\"%f %f %f\"\n", clr.x, clr.y, clr.z);


		float f = 1.0f;
		if (light->GetLightMultiplier())
		{
			light->GetLightMultiplier()->GetPropertyValue(f);
		}

		Indent(fp); fprintf(fp, "multiplier=\"%f\"\n", f);

		// save attenuation start / end
		float fl;
		fl =501.0f;
		if (light->GetLightAttenStart())
		{
			light->GetLightAttenStart()->GetPropertyValue(fl);
		}
		else
		{
			fl = ls.attenStart;
		}
		
		float fl_end = 100.0f;
		if (light->GetLightAttenEnd())
		{
			light->GetLightAttenEnd()->GetPropertyValue(fl_end);
		}
		else
		{
			fl_end = ls.attenEnd;
		}

		if (type != "dir")
		{
			Indent(fp); fprintf(fp, "attenstart=\"%f\"\n", fl);
			Indent(fp); fprintf(fp, "attenend=\"%f\"\n", fl_end);
		}

		unsigned long target_node_id = 0;
		if (target)
		{
			Indent(fp); fprintf(fp, "target=\"%s\"\n", 
				light->GetLightTarget()->GetName());
		}

		if (lt == IGameLight::IGAME_TSPOT || lt == IGameLight::IGAME_FSPOT)
		{
			if (light->GetLightFallOff())
			{
				light->GetLightFallOff()->GetPropertyValue(f);
			}
			else
			{
				f = ls.fallsize;
			}

			Indent(fp); fprintf(fp, "falloff=\"%f\"\n", f);

			if (light->GetLightHotSpot())
			{
				light->GetLightHotSpot()->GetPropertyValue(f);
			}
			else
			{
				f = ls.hotsize;
			}

			Indent(fp); fprintf(fp, "hotspot=\"%f\"\n", f);
		}

		indent--;
		Indent(fp); fprintf(fp, "/>\n");

		indent--;
		Indent(fp); fprintf(fp, "</object>\n\n");
	}
}

// ----------------------------------------------------------------------
// animation plugin
// ----------------------------------------------------------------------
static PRS GMatrixToPRS(const GMatrix &mat) {
	Vector3 pos(mat.Translation().x, mat.Translation().y, mat.Translation().z);
	Quaternion rot(mat.Rotation().w, mat.Rotation().x, mat.Rotation().y, mat.Rotation().z);
	Vector3 scale(mat.Scaling().x, mat.Scaling().y, mat.Scaling().z);
	return PRS(pos, rot, scale);
}
void AnimeyExportPlugin::ProcessSingleNode(IGameNode* node)
{
	// get the corresponding object
	IGameObject* obj = node->GetIGameObject();
	if (!obj)
	{
		return;
	}

	Indent(fp); fprintf(fp, "<xform name=\"%s\">\n", node->GetName());
	indent++;

	// get default local PRS
	PRS def_prs = GMatrixToPRS(node->GetLocalTM());
	Indent(fp); fprintf(fp, "<defprs \n");
	indent++;

	Indent(fp); fprintf(fp, "pos=\"%f %f %f\"\n", def_prs.GetPosition().x, 
		def_prs.GetPosition().y, def_prs.GetPosition().z);
	Indent(fp); fprintf(fp, "rot=\"%f %f %f %f\"\n", def_prs.GetRotation().v.x, 
		def_prs.GetRotation().v.y, def_prs.GetRotation().v.z, def_prs.GetRotation().s);
	Indent(fp); fprintf(fp, "scale=\"%f %f %f\"\n", def_prs.GetScaling().x, 
		def_prs.GetScaling().y, def_prs.GetScaling().z);

	indent--;
	Indent(fp); fprintf(fp, "/>\n");


	IGameKeyTab pos_keys, rot_keys, scale_keys;
	IGameControl* control = node->GetIGameControl(); 

	IGameKeyTab tm_keys;

	// create a new KeyframeChunk
	if (control->GetFullSampledKeys(tm_keys, 1, IGameControlType(IGAME_TM), true))
	{
		for (unsigned int i=0; i<tm_keys.Count(); i++)
		{
			PRS kf = GMatrixToPRS(tm_keys[i].sampleKey.gval);
			Indent(fp); fprintf(fp, "<keyframe id=\"%d\"\n", i);
			indent++;
			
			Indent(fp); fprintf(fp, "pos=\"%f %f %f\"\n", kf.GetPosition().x,
				kf.GetPosition().y, kf.GetPosition().z);
			Indent(fp); fprintf(fp, "rot=\"%f %f %f %f\"\n", kf.GetRotation().v.x,
				kf.GetRotation().v.y, kf.GetRotation().v.z, kf.GetRotation().s);
			Indent(fp); fprintf(fp, "scale=\"%f %f %f\"\n", kf.GetScaling().x,
				kf.GetScaling().y, kf.GetScaling().z);

			indent--;
			Indent(fp); fprintf(fp, "/>\n");
		}
	}

	
	indent--;
	Indent(fp); fprintf(fp, "</xform>\n");

	node->ReleaseIGameObject();
	obj = 0;
}

void AnimeyExportPlugin::ProcessNode(IGameNode* node)
{
	// process current node
	ProcessSingleNode(node);

	// process children
	for (unsigned int i=0; i<node->GetChildCount(); i++)
	{
		ProcessNode(node->GetNodeChild(i));
	}
}

int AnimeyExportPlugin::DoExport(const TCHAR *name, ExpInterface *ei,
		Interface *i, BOOL suppressPrompts,
		DWORD options)
{
	scene = GetIGameInterface();
	if (!scene)
		return false;

	fp = fopen(FixExtension(name).c_str(), "w+");
	if (!fp) return false;

	fprintf(fp, "<?xml version=\"1.0\"?>\n");
	fprintf(fp, "<animation name=\"%s\" fps=\"%d\">\n", 
		FixExtension(GetFilename(name)).c_str(), GetFrameRate());
	indent++;

	// Set D3D coord system
	GetConversionManager()->SetCoordSystem(IGameConversionManager::IGAME_D3D); 
	scene->InitialiseIGame(false);

	// process nodes
	for (unsigned int i=0; i<scene->GetTopLevelNodeCount(); i++)
	{
		ProcessNode(scene->GetTopLevelNode(i));
	}


	indent--;
	fprintf(fp, "</scene>\n");
	fclose(fp);

	if (scene)
	{
		scene->ReleaseIGame();
		scene = 0;
	}
	return TRUE;
}







